#include <xc.h>
#include <pic.h>

// CONFIG1
#pragma config FOSC = INTOSC    // Oscillator Selection (ECH, External Clock, High Power Mode (4-32 MHz): device clock supplied to CLKIN pin)
#pragma config WDTE = OFF       // Watchdog Timer Enable (WDT disabled)
#pragma config PWRTE = OFF      // Power-up Timer Enable (PWRT disabled)
#pragma config MCLRE = ON       // MCLR Pin Function Select (MCLR/VPP pin function is MCLR)
#pragma config CP = OFF         // Flash Program Memory Code Protection (Program memory code protection is disabled)
#pragma config CPD = OFF        // Data Memory Code Protection (Data memory code protection is disabled)
#pragma config BOREN = ON       // Brown-out Reset Enable (Brown-out Reset enabled)
#pragma config CLKOUTEN = OFF   // Clock Out Enable (CLKOUT function is disabled. I/O or oscillator function on the CLKOUT pin)
#pragma config IESO = ON        // Internal/External Switchover (Internal/External Switchover mode is enabled)
#pragma config FCMEN = ON       // Fail-Safe Clock Monitor Enable (Fail-Safe Clock Monitor is enabled)

// CONFIG2
#pragma config WRT = OFF        // Flash Memory Self-Write Protection (Write protection off)
#pragma config VCAPEN = OFF     // Voltage Regulator Capacitor Enable bit (Vcap functionality is disabled on RA6.)
#pragma config PLLEN = ON       // PLL Enable (4x PLL enabled)
#pragma config STVREN = ON      // Stack Overflow/Underflow Reset Enable (Stack Overflow or Underflow will cause a Reset)
#pragma config BORV = LO        // Brown-out Reset Voltage Selection (Brown-out Reset Voltage (Vbor), low trip point selected.)
#pragma config LPBOR = OFF      // Low Power Brown-Out Reset Enable Bit (Low power brown-out is disabled)
#pragma config LVP = ON         // Low-Voltage Programming Enable (Low-voltage programming enabled)

typedef long long ll;
typedef unsigned long long ull;
typedef unsigned char uint8_t;
typedef unsigned int uint16_t;
typedef unsigned char bool;
#define ULL_MAX 0xffffffff
#define INT_MAX 32767
unsigned global_timestamp=0;

unsigned timediff=0,last_magnet=0;

#define ROW_LOG2 6
#define ROW (1<<ROW_LOG2)
uint8_t data[ROW][2];

void tmr0_routine(){
    //which slide of led to light up
    static bool slide_id=0,col_id=0;
    //if which ==0 ,the row to show
    static int row=0;
    static int col=0;    //last timestamp to switch the row
    if(col_id&1)slide_id^=1;
    col_id^=1;
    
    if(global_timestamp>timediff){
        global_timestamp=0;
        row=(row+1)&(ROW-1);
    }
    LATC=0x0f;
    LATB=data[(row+(slide_id<<(ROW_LOG2/2)))&(ROW-1)][col_id];
    LATC=~((1<<col_id)<<(slide_id<<1));
}

void interrupt int_routine(){
    if(INTCONbits.TMR0IF){
        //INTCONbits.GIE=0;
        ++global_timestamp;
        //INTCONbits.GIE=1;
        tmr0_routine();
        TMR0=0xf0;
        INTCONbits.TMR0IF=0;
    }
}
void int_init(){
    OPTION_REG=0x00; //1:2
    OSCCON=0b01111010;//16M
    INTCONbits.GIE=1;
    INTCONbits.PEIE=1;
    INTCONbits.TMR0IE=1;
}

void int_led(){
    PORTB=0;
    TRISB=0;
    LATB=1; 
    ANSELB=0;
    PORTC=0;
    TRISC=0;
    //1:yellow 2:red 3:blue 4:green
    LATC=0;
}
void init_adc(){
    ADCON0bits.ADRMD=0; //12bits data
    ADCON0bits.CHS=3; //AN3
    //ADCON0bits.GO
    ADCON0bits.ADON=1;//ADC??
    ADCON1bits.ADFM=0; //????
    ADCON1bits.ADCS=0; //FOSC/2
    ADCON1bits.ADNREF=0; //REF- = VSS
    ADCON1bits.ADPREF=0; //REF+ = VDD
    ADCON2=0b00001111;
    
    TRISAbits.TRISA3=1;
    ANSELAbits.ANSA3=1;//anolg
}
void init_data(int cho){
    int i;
    if(cho==1){
        for(i=0;i<16;i++){
            data[i][0]=0x0f;
            data[i][1]=0xf0;
        }
        for(i=16;i<32;i++){
            data[i][0]=0xf0;
            data[i][1]=0x0f;
        }
        for(i=32;i<48;i++){
            data[i][0]=0x0f;
            data[i][1]=0xf0;
        }
        for(i=32;i<48;i++){
            data[i][0]=0xf0;
            data[i][1]=0x0f;
        }
    }else if(cho==2){
        data[0][0]=0x01;data[0][1]=0x80;
        data[1][0]=0x03;data[1][1]=0xb0;
        data[2][0]=0x07;data[2][1]=0xe0;
        data[3][0]=0x0f;data[3][1]=0xf0;
        data[4][0]=0x1f;data[4][1]=0xf8;
        data[5][0]=0x3f;data[5][1]=0xfb;
        data[6][0]=0x7f;data[6][1]=0xfe;
        data[7][0]=0xff;data[7][1]=0xff;
        data[8][0]=0xff;data[8][1]=0xff;
        data[9][0]=0x7f;data[9][1]=0xfe;
        data[10][0]=0x3f;data[10][1]=0xfb;
        data[11][0]=0x1f;data[11][1]=0xf8;
        data[12][0]=0x0f;data[12][1]=0xf0;
        data[13][0]=0x07;data[13][1]=0xe0;
        data[14][0]=0x03;data[14][1]=0xb0;
        data[15][0]=0x01;data[15][1]=0x80;
    }
    
}
#define MID 2200
#define K 250
void main(void) {
    int adc_res;
    char tmp=1;
    unsigned char laststate=0;
    ull first_in=0;
    int_led();
    int_init();
    init_adc();
    init_data(2);
    timediff=26;
    last_magnet=0;

    while(1){
        if(ADCON0bits.GO==0){
            continue;
            adc_res=ADRESH;
            adc_res<<=4;
            adc_res|=ADRESL>>4;
            if(ADRESL&1)adc_res=-adc_res;
            if(adc_res<MID-100){//magnet
                if(laststate==0){
                    if(first_in==0){
                        first_in=global_timestamp;
                        continue;
                    }else if(global_timestamp-first_in<500){
                        continue;
                    }
                    INTCONbits.GIE=0;
                    if(global_timestamp>last_magnet)timediff=(global_timestamp-last_magnet)>>ROW_LOG2;
                    else timediff=((ULL_MAX-last_magnet)+global_timestamp)>>ROW_LOG2;
                    last_magnet=global_timestamp;
                    INTCONbits.GIE=1;
                    //LATB=0xff;
                    //if(tmp==8)tmp=1;
                    //else tmp<<=1;
                    //LATC=~tmp;
                    //deal something
                    laststate=1;
                }
            }else{
                if(laststate==1){
                    first_in=0;
                    laststate=0;
                }
            }
            ADCON0bits.GO=1;
        }
    }
}
